package vip.xiaonuo.common.lock;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@Component
public class DistributedLockExecutor {

    private final RedissonClient redissonClient;

    public DistributedLockExecutor(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    /**
     * 执行分布式锁保护的操作
     * @param lockKey 锁的键
     * @param waitTime 等待锁的最长时间（毫秒）
     * @param leaseTime 锁持有时间（毫秒）
     * @param action 要执行的操作
     * @param <T> 返回类型
     * @return 操作结果
     */
    public <T> T executeWithLock(String lockKey,
                                 long waitTime,
                                 long leaseTime,
                                 Supplier<T> action) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试获取锁
            boolean isLocked = lock.tryLock(waitTime, leaseTime, TimeUnit.MILLISECONDS);
            if (isLocked) {
                return action.get();
            } else {
                throw new LockAcquisitionException("Failed to acquire lock for key: " + lockKey);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new LockInterruptedException("Lock acquisition interrupted", e);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 执行无返回值的分布式锁操作
     * @param lockKey 锁的键
     * @param waitTime 等待锁的最长时间（毫秒）
     * @param leaseTime 锁持有时间（毫秒）
     * @param action 要执行的操作
     */
    public void executeWithLock(String lockKey,
                                long waitTime,
                                long leaseTime,
                                Runnable action) {
        executeWithLock(lockKey, waitTime, leaseTime, () -> {
            action.run();
            return null;
        });
    }

    public static class LockAcquisitionException extends RuntimeException {
        public LockAcquisitionException(String message) {
            super(message);
        }
    }

    public static class LockInterruptedException extends RuntimeException {
        public LockInterruptedException(String message, Throwable cause) {
            super(message, cause);
        }
    }
}
